using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using GraphMyCode.Client.AssemblyService;
using GraphMyCode.Client.Scalling;

namespace GraphMyCode.Client.ViewModels
{
	public class GraphViewModel : ViewModelBase
	{
		private readonly ObservableCollection<ElementViewModel> elements;

		private readonly Dictionary<int, NodeViewModel> vertexLookup;

		protected GraphViewModel()
		{
			elements = new ObservableCollection<ElementViewModel>();
			vertexLookup = new Dictionary<int, NodeViewModel>();
		}
		public GraphViewModel(GraphDto graph, ScaleEngine scaleEngine, ExportType type)
			: this()
		{
			foreach (var vertex in graph.vertices)
			{
				NodeViewModel node = new NodeViewModel(vertex, scaleEngine, type);
				vertexLookup.Add(vertex.Id, node);
				AddNode(node);
			}

			foreach (var edgeModel in graph.edges)
			{
				EdgeViewModel edge = new EdgeViewModel(edgeModel, scaleEngine)
				                     	{
				                     		FromNode = vertexLookup[edgeModel.Source.Id],
				                     		ToNode = vertexLookup[edgeModel.Target.Id]
				                     	};
				AddEdge(edge);
			}
		}

		public IEnumerable<NodeViewModel> Nodes
		{
			get { return Elements.OfType<NodeViewModel>(); }
		}

		public IEnumerable<EdgeViewModel> Edges
		{
			get
			{
				return Elements.OfType<EdgeViewModel>();
			}
		}

		public ObservableCollection<ElementViewModel> Elements
		{
			get { return elements; }
		}

		public void AddEdge(EdgeViewModel edge)
		{
			edge.FromNode.OutEdges.Add(edge);
			edge.ToNode.InEdges.Add(edge);

			Elements.Add(edge);

			if (!Nodes.Contains(edge.FromNode))
				Elements.Add(edge.FromNode);
			if (!Nodes.Contains(edge.ToNode))
				Elements.Add(edge.ToNode);
		}

		public void AddNode(NodeViewModel node)
		{
			if (!Nodes.Contains(node))
			{
				Elements.Add(node);
			}
		}
	}
}